package com.ssy.lingxi.purchase.serviceimpl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.ssy.lingxi.common.constant.order.OrderPurchaseProcessTypeEnum;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.order.api.feign.OrderFeignService;
import com.ssy.lingxi.order.api.model.vo.request.OrderPurchaseProcessFeignVO;
import com.ssy.lingxi.order.api.model.vo.response.OrderPurchaseProcessFeignDetailVO;
import com.ssy.lingxi.purchase.entity.PurchaseInnerHistory;
import com.ssy.lingxi.purchase.entity.PurchaseProduct;
import com.ssy.lingxi.purchase.entity.PurchaseRequisition;
import com.ssy.lingxi.purchase.entity.QPurchaseRequisition;
import com.ssy.lingxi.purchase.model.enums.PurchaseConstants;
import com.ssy.lingxi.purchase.model.enums.RequisitionInnerStatusEnum;
import com.ssy.lingxi.purchase.model.request.RequisitionPageReq;
import com.ssy.lingxi.purchase.model.request.RequisitionProductReq;
import com.ssy.lingxi.purchase.model.response.*;
import com.ssy.lingxi.purchase.repository.PurchaseInnerHistoryRepository;
import com.ssy.lingxi.purchase.repository.PurchaseProductRepository;
import com.ssy.lingxi.purchase.service.ICommonService;
import com.ssy.lingxi.purchase.utils.NumberUtil;
import com.ssy.lingxi.workflow.api.feign.ProcessFeign;
import com.ssy.lingxi.workflow.api.model.vo.request.InternalProcessQueryVO;
import com.ssy.lingxi.workflow.api.model.vo.request.TaskExecuteVO;
import com.ssy.lingxi.workflow.api.model.vo.request.TaskStartVO;
import com.ssy.lingxi.workflow.api.model.vo.response.ComplexTaskCompleteVO;
import com.ssy.lingxi.workflow.api.model.vo.response.SimpleProcessDefVO;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Sort;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.Column;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author wyx
 * @version 2.0.0
 * @date 2021-10-28
 */
@Service
public class CommonServiceImpl implements ICommonService {
    @Resource
    private PurchaseProductRepository purchaseProductRepository;
    @Resource
    private ProcessFeign processFeign;
    @Resource
    private OrderFeignService orderFeignService;
    @Resource
    private PurchaseInnerHistoryRepository purchaseInnerHistoryRepository;
    @Resource
    private JPAQueryFactory jpaQueryFactory;


    /**
     * 校验请购单商品接口参数
     * @param requisition 订单
     * @param products    订单物料列表
     * @param isCreate    是否新增，true表示新增， false表示修改
     * @return 订单总金融
     */
    @Override
    public Wrapper<PurchaseProductCheckRes> checkRequisitionProduct(PurchaseRequisition requisition, List<RequisitionProductReq> products, boolean isCreate) {
        //商品总金额
        BigDecimal productAmount = BigDecimal.ZERO;
        //请购总数量
        BigDecimal quantity = BigDecimal.ZERO;

        List<PurchaseProduct> productList = new ArrayList<>();
        for (RequisitionProductReq productReq : products) {
            PurchaseProduct product = new PurchaseProduct();
            product.setPurchaseRequisition(requisition);
            product.setProductId(productReq.getProductId());
            product.setProductNo(productReq.getProductNo());
            product.setName(productReq.getName());
            product.setCategory(productReq.getCategory());
            product.setBrand(StringUtils.hasLength(productReq.getBrand()) ? productReq.getBrand() : "");
            product.setSpec(StringUtils.hasLength(productReq.getSpec()) ? productReq.getSpec() : "");
            product.setUnit(productReq.getUnit());
            product.setPrice(productReq.getPrice());
            product.setQuantity(productReq.getQuantity());
            product.setAmount(NumberUtil.isNullOrZero(productReq.getPrice()) ? BigDecimal.ZERO : productReq.getPrice().multiply(productReq.getQuantity()));
            //新增或修改已转采购订单数量设为0
            product.setTransferQuantity(BigDecimal.ZERO);
            product.setGoodsGroup(productReq.getGoodsGroup());
            product.setManuFacturer(productReq.getManuFacturer());
            product.setPlaceOrigin(productReq.getPlaceOrigin());
            product.setRemark(productReq.getRemark());
            //统计商品总金额
            productAmount = productAmount.add(product.getAmount());
            //统计请购总数量
            quantity = quantity.add(product.getQuantity());

            productList.add(product);
        }

        //如果是修改，删除原有数据
        if (!isCreate) {
            purchaseProductRepository.deleteByPurchaseRequisition(requisition);
        }
        purchaseProductRepository.saveAll(productList);

        requisition.setProducts(new HashSet<>(productList));
        return Wrapper.success(new PurchaseProductCheckRes(productAmount, quantity));
    }

    /**
     * 启动订单流程
     * @param requisition 请购单
     * @return 启动结果
     */
    @Override
    public Wrapper<PurchaseProcessTaskRes> startPurchaseProcess(PurchaseRequisition requisition) {
        TaskStartVO startVO = new TaskStartVO();
        startVO.setProcessKey(requisition.getTask().getProcessKey());
        startVO.setMemberId(requisition.getBuyerMemberId());
        startVO.setRoleId(requisition.getBuyerRoleId());
        startVO.setDataId(requisition.getId());
        //这里是启动流程
        Wrapper<ComplexTaskCompleteVO> result = processFeign.startProcess(startVO);
        if (result.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(result.getCode(), result.getMessage());
        }

        PurchaseProcessTaskRes taskResult = new PurchaseProcessTaskRes(result.getData());

        //供应商内部状态，以及下一步的任务Id
        requisition.setBuyerInnerStatus(taskResult.getBuyerInnerStatus());
        requisition.getTask().setTaskId(taskResult.getTaskId());

        return Wrapper.success(taskResult);
    }

    /**
     * 查询（采购）会员采购流程配置
     * @param buyerMemberId           采购会员Id
     * @param buyerRoleId             采购会员角色Id
     * @param purchaseProcessTypeEnum 采购流程类型
     * @return 查询结果
     */
    @Override
    public Wrapper<OrderPurchaseProcessFeignDetailVO> findPurchaseProcess(Long buyerMemberId, Long buyerRoleId, OrderPurchaseProcessTypeEnum purchaseProcessTypeEnum) {
        OrderPurchaseProcessFeignVO feignVO = new OrderPurchaseProcessFeignVO();
        feignVO.setMemberId(buyerMemberId);
        feignVO.setRoleId(buyerRoleId);
        feignVO.setProcessTypeEnum(purchaseProcessTypeEnum);
        return orderFeignService.findBuyerPurchaseProcess(feignVO);
    }

    /**
     * 保存订单内部流转记录
     * @param memberId         登录用户会员Id
     * @param roleId           登录用户会员角色Id
     * @param userName         登录用户姓名
     * @param organizationName 登录用户组织机构名称
     * @param jobTitle         登录用户职位
     * @param orderId          订单Id列表
     * @param operation        操作
     * @param statusName       订单状态名称
     * @param remark           备注
     */
    @Async
    @Override
    public void savePurchaseInnerHistory(Long memberId, Long roleId, String userName, String organizationName, String jobTitle, Long orderId, String operation, String statusName, String remark) {
        PurchaseInnerHistory innerHistory = new PurchaseInnerHistory();
        innerHistory.setCreateTime(LocalDateTime.now());
        innerHistory.setOrderId(orderId);
        innerHistory.setMemberId(memberId);
        innerHistory.setRoleId(roleId);
        innerHistory.setOperator(userName);
        innerHistory.setDepartment(organizationName);
        innerHistory.setJobTitle(jobTitle);
        innerHistory.setOperation(operation);
        innerHistory.setStatusName(statusName);
        innerHistory.setRemark(StringUtils.hasLength(remark) ? remark.trim() : "");
        purchaseInnerHistoryRepository.save(innerHistory);
    }

    /**
     * 查询请购单流程
     * @param processKey     流程Key
     * @param taskId         流程步骤任务Id
     * @param vendorMemberId 供应商会员Id
     * @return 查询结果
     */
    @Override
    public Wrapper<ProcessStepsRes> findRequisitionProcessSteps(String processKey, String taskId, Long vendorMemberId) {
        InternalProcessQueryVO queryVO = new InternalProcessQueryVO();
        queryVO.setProcessKey(processKey);
        queryVO.setTaskId(taskId);
        queryVO.setMemberId(vendorMemberId);
        Wrapper<SimpleProcessDefVO> result = processFeign.findSimpleInternalTaskDefinitions(queryVO);
        if (result.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(result.getCode(), result.getMessage());
        }

        ProcessStepsRes stepsRes = new ProcessStepsRes();
        stepsRes.setInnerSteps(result.getData().getTasks().stream().map(internalTask -> new WorkFlowStepRes(internalTask.getTaskStep(), internalTask.getTaskName(), internalTask.getRoleName())).sorted(Comparator.comparingInt(WorkFlowStepRes::getStep)).collect(Collectors.toList()));
        stepsRes.setCurrentInnerStep(StringUtils.hasLength(taskId) ? result.getData().getCurrentStep() : stepsRes.getInnerSteps().stream().max(Comparator.comparingInt(WorkFlowStepRes::getStep)).map(WorkFlowStepRes::getStep).orElse(0));
        return Wrapper.success(stepsRes);
    }

    /**
     * 订单商品汇总信息
     * @param requisition 订单
     * @return 订单商品汇总
     */
    @Override
    public PurchaseProductRes purchaseProducts(PurchaseRequisition requisition) {
        PurchaseProductVO summaryRes = new PurchaseProductVO();
        //商品总金额
        summaryRes.setProductAmount(NumberUtil.formatAmount(requisition.getProductAmount()));
        //请购总数量
        summaryRes.setQuantity(NumberUtil.formatToInteger(requisition.getQuantity()));
        //已转采购订单总数量
        summaryRes.setTransferQuantity(NumberUtil.formatToInteger(requisition.getTransferQuantity()));

        List<PurchaseProduct> orderProducts = purchaseProductRepository.findByPurchaseRequisition(requisition, Sort.by("id").ascending());
        summaryRes.setProducts(orderProducts.stream().map(product -> {
            PurchaseProductDetailVO detailVO = new PurchaseProductDetailVO();
            detailVO.setId(product.getId());
            detailVO.setProductId(product.getProductId());
            detailVO.setProductNo(StringUtils.hasLength(product.getProductNo()) ? product.getProductNo() : "");
            detailVO.setName(product.getName());
            detailVO.setCategory(product.getCategory());
            detailVO.setBrand(product.getBrand());
            detailVO.setUnit(product.getUnit());
            detailVO.setSpec(StringUtils.hasLength(product.getSpec()) ? product.getSpec() : "");
            detailVO.setQuantity(NumberUtil.formatToInteger(product.getQuantity()));
            detailVO.setTransferQuantity(NumberUtil.formatToInteger(product.getTransferQuantity()));
            detailVO.setPrice(product.getPrice());
            detailVO.setAmount(NumberUtil.formatAmount(product.getAmount()));
            BeanUtils.copyProperties(product, detailVO);
            return detailVO;
        }).collect(Collectors.toList()));

        PurchaseProductRes productRes = new PurchaseProductRes();
        productRes.setProductVO(summaryRes);
        return productRes;
    }

    /**
     * 查询采购订单内部流转记录
     * @param buyerMemberId 采购会员Id
     * @param buyerRoleId   采购会员角色Id
     * @param orderId       订单Id
     * @return 内部流转记录
     */
    @Override
    public List<PurchaseInnerHistoryVO> listBuyerOrderInnerHistories(Long buyerMemberId, Long buyerRoleId, Long orderId) {
        return purchaseInnerHistoryRepository.findByMemberIdAndRoleIdAndOrderId(buyerMemberId, buyerRoleId, orderId, Sort.by("id").descending()).stream().map(historyDO -> {
            PurchaseInnerHistoryVO historyVO = new PurchaseInnerHistoryVO();
            historyVO.setId(historyDO.getId());
            historyVO.setCreateTime(historyDO.getCreateTime().format(PurchaseConstants.DEFAULT_TIME_FORMATTER));
            historyVO.setOperator(historyDO.getOperator());
            historyVO.setDepartment(historyDO.getDepartment());
            historyVO.setJobTitle(historyDO.getJobTitle());
            historyVO.setOperation(historyDO.getOperation());
            historyVO.setStatusName(historyDO.getStatusName());
            historyVO.setRemark(historyDO.getRemark());
            return historyVO;
        }).collect(Collectors.toList());
    }

    /**
     * 执行请购单下个流程
     * @param requisition 请购单
     * @param agree       执行下个流程跳转参数
     * @return 内部流转记录
     */
    @Override
    public Wrapper<PurchaseProcessTaskRes> executeRequisitionProcess(PurchaseRequisition requisition, Integer agree) {
        TaskExecuteVO executeVO = new TaskExecuteVO();
        executeVO.setProcessKey(requisition.getTask().getProcessKey());
        executeVO.setTaskId(requisition.getTask().getTaskId());
        executeVO.setMemberId(requisition.getBuyerMemberId());
        executeVO.setRoleId(requisition.getBuyerRoleId());
        executeVO.setDataId(requisition.getId());
        executeVO.setAgree(agree == null ? -1 : agree);

        Wrapper<ComplexTaskCompleteVO> result = processFeign.completeTask(executeVO);
        if (result.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(result.getCode(), result.getMessage());
        }

        PurchaseProcessTaskRes taskResult = new PurchaseProcessTaskRes(result.getData());

        requisition.setBuyerInnerStatus(taskResult.getBuyerInnerStatus());
        requisition.getTask().setTaskId(taskResult.getTaskId());
        return Wrapper.success(taskResult);
    }

    /**
     * 公共的请购单分页实现
     * @param loginUser          登录用户信息
     * @param req                分页请求参数
     * @param buyerInnerStatus   内部状态集合
     * @param isTransferPurchase 是否为请购单转采购订单分页
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<RequisitionPageRes>> getBaseRequisitionPage(UserLoginCacheDTO loginUser, RequisitionPageReq req, List<Integer> buyerInnerStatus, Boolean isTransferPurchase) {
        //构造查询条件
        BooleanBuilder predicates = new BooleanBuilder();
        //表实体
        QPurchaseRequisition qRequisition = QPurchaseRequisition.purchaseRequisition;

        predicates.and(qRequisition.buyerMemberId.eq(loginUser.getMemberId()));
        predicates.and(qRequisition.buyerRoleId.eq(loginUser.getMemberRoleId()));
        if (StrUtil.isNotBlank(req.getRequisitionNo())) {
            predicates.and(qRequisition.requisitionNo.like("%" + req.getRequisitionNo() + "%"));
        }
        if (StrUtil.isNotBlank(req.getDigest())) {
            predicates.and(qRequisition.digest.like("%" + req.getDigest() + "%"));
        }
        if (StrUtil.isNotBlank(req.getMemberName())) {
            predicates.and(qRequisition.vendorMemberName.like("%" + req.getMemberName() + "%"));
        }
        if (StrUtil.isNotBlank(req.getStartDate())) {
            predicates.and(qRequisition.deliverTime.goe(LocalDateTime.parse(req.getStartDate().concat(" 00:00:00"), PurchaseConstants.DEFAULT_TIME_FORMATTER)));
        }
        if (StrUtil.isNotBlank(req.getEndDate())) {
            predicates.and(qRequisition.deliverTime.loe(LocalDateTime.parse(req.getEndDate().concat(" 00:00:00"), PurchaseConstants.DEFAULT_TIME_FORMATTER)));
        }
        if (StrUtil.isNotBlank(req.getDepartment())) {
            predicates.and(qRequisition.department.like("%" + req.getDepartment() + "%"));
        }
        if (StrUtil.isNotBlank(req.getPurpose())) {
            predicates.and(qRequisition.purpose.like("%" + req.getPurpose() + "%"));
        }
        if (req.getInnerStatus() != null) {
            predicates.and(qRequisition.buyerInnerStatus.eq(req.getInnerStatus()));
        }
        if (req.getInnerStatus() == null && CollUtil.isNotEmpty(buyerInnerStatus)) {
            predicates.and(qRequisition.buyerInnerStatus.in(buyerInnerStatus));
        }
        if (isTransferPurchase != null && isTransferPurchase) {
            predicates.and(qRequisition.buyerInnerStatus.eq(RequisitionInnerStatusEnum.BUYER__SUBMITTED.getCode())).and(qRequisition.transferQuantity.lt(qRequisition.quantity));
        }
        if (ObjectUtil.isNotNull(req.getRequisitioner())) {
            predicates.and(qRequisition.requisitioner.like("%" + req.getRequisitioner() + "%"));
        }

        JPAQuery<PurchaseRequisition> query = jpaQueryFactory.select(qRequisition).from(qRequisition).where(predicates);

        long totalCount = query.fetchCount();

        List<RequisitionPageRes> requisitionList = query.orderBy(qRequisition.id.desc()).offset(req.getCurrentOffset()).limit(req.getPageSize()).fetch().stream().map(RequisitionPageRes::new).collect(Collectors.toList());

        return Wrapper.success(new PageData<>(totalCount, requisitionList));
    }
}